package com.gene.tlonpo.service.remote.common.protof;

import com.gene.tlonpo.service.remote.common.enums.ModeEnum;
import com.gene.tlonpo.service.remote.common.enums.ProtofVersion;
import com.gene.tlonpo.service.remote.common.model.DataDto;
import com.gene.tlonpo.service.remote.common.model.DataRespDto;
import com.gene.tlonpo.util.KryoSerializerUtil;
import io.netty.buffer.ByteBuf;
import lombok.Getter;

import java.io.Serializable;
import java.nio.charset.StandardCharsets;

/**
 * @author geneX
 * 通信协议
 */
public class TlonpoProtof implements Serializable {
    private static final long serialVersionUID = -3798404588913655433L;

    private static final Byte MARK_LENGTH = (byte) 6;

    private static final String MARK = "tlonpo";
    /**
     * 协议标识，string
     */
    private String mark = MARK;
    /**
     * 消息头
     */
    private ProtofHeader header;

    /**
     * 消息体。现在直接obj
     */
    @Getter
    private Object body;

    public TlonpoProtof(ProtofHeader header, Object body) {
        //数据校验
        this.header = header;
        this.body = body;
    }


    public boolean isRequest() {
        return this.header.isReqeust();
    }

    public boolean isResponse() {
        return this.header.isResponse();
    }


    /**
     * 协议校验
     *
     * @param in 接受数据
     * @return
     */
    public static TlonpoProtof decode(final ByteBuf in) {
        //mark
        byte[] mark = new byte[MARK_LENGTH];
        in.readBytes(mark, 0, MARK_LENGTH);
        String inMark = new String(mark, StandardCharsets.UTF_8);
        if (!MARK.equals(inMark)) {
            throw new RuntimeException("protof not adapt");
        }

        //version
        byte versionLength = in.readByte();
        byte[] version = new byte[versionLength];
        in.readBytes(version, 0, versionLength);
        String inVersion = new String(version, StandardCharsets.UTF_8);
        if (!ProtofVersion.V1.getVersionStr().equals(inVersion)) {
            throw new RuntimeException("protof not adapt");
        }

        //校验header
        //version
        //模式确定
        byte inMode = in.readByte();
        ModeEnum byMode = ModeEnum.getByMode(inMode);
        if (byMode == null) {
            throw new RuntimeException("protof not adapt of property mode");
        }

        //读取数据
        int msgLength = in.readInt();
        byte[] msgBytes = new byte[msgLength];
        in.readBytes(msgBytes, 0, msgLength);

        Object msg = null;
        if (byMode == ModeEnum.REQUEST) {
            msg = KryoSerializerUtil.deserializer(msgBytes, DataDto.class);
        } else {
            msg = KryoSerializerUtil.deserializer(msgBytes, DataRespDto.class);
        }

        ProtofHeader header = new ProtofHeader(inVersion, byMode);

        return new TlonpoProtof(header, msg);
    }

    public void encode(ByteBuf out){
        //mark
        byte[] markBytes = this.mark.getBytes(StandardCharsets.UTF_8);
        out.writeBytes(markBytes);
        //version长度
        byte[] versionBytes = this.header.getVersion().getBytes(StandardCharsets.UTF_8);
        out.writeByte(versionBytes.length);
        //version
        out.writeBytes(versionBytes);
        //mode
        out.writeByte(this.header.getMode().getMode());
        //bodyLength
        byte[] bodyBytes = KryoSerializerUtil.serializer(this.body);
        out.writeInt(bodyBytes.length);
        //body
        out.writeBytes(bodyBytes);
    }







}
